<?

class mysqlCheck{

	//Variables
	var $Needed = Array("Id"=> "INT", "tmsCreate"=> "VARCHAR(30)","userCreate"=> "VARCHAR(30)","tmsEdit"=> "VARCHAR(30)","userEdit"=>"VARCHAR(30)");
	var $tabType= Array("int","string","varchar","boolean","password","image","order","date","text");


	//----------------------------------------------//
	// VERIFICATION									//
	//----------------------------------------------//

	//Fonction associee a Check qui verifie les donnees entre sql et le schema
	//Si elle n'existe pas on la cree, et si la creation ne marche pas on renvoie une erreur
	function initData () {
		if (!$this->getStructureSql()) $this->generateSqlTable();
		$this->Compare();
	}

	//Compare sql et le schema
	function Compare() {
		$erreur = false;
		//On compare les proprietes et les clefs etrangeres
		if ($this->compareProperties() || $this->compareFKeys()){
			$this->getStructureSql();
			if ($this->compareProperties() || $this->compareFKeys()){
				$erreur = true;
			}
		}
		//On teste si il existe un heritage potentiel
		if ($this->Heritage && !$this->verifyInheritStruct()) {
			$this->createInheritStruct();
		}
		//On teste si l objectClass est reflexif
		if ($this->isReflexive() && !$this->verifyIntervalIndex()) {
			//Dans ce cas on met en place les index intervallaires
			$this->createIntervalIndex();
		}
		// @todo : Création des indexs
		return $erreur;
	}

	//Renvoie la structure de la table et si elle echoue appelle la creation dune nouvelle table.
	function createData() {
		$sql="SHOW COLUMNS FROM `".$this->Prefix.$this->titre."`";
		if (!mysql_query($sql)) mysqlDriver::generateSqlTable();
	}

	//Renvoie la structure SQL
	function getStructureSql() {
		//On execute la requete qui renvoie la structure
		$sql="SHOW COLUMNS FROM `".$this->Prefix.$this->titre."`";
		$resql=$this->executeSql($sql,"CHECK");
		if (is_object($resql)) return false;
		$i = 0;
		//On range le resultat dans un tableau
		foreach($resql as $tab){
			//La requete s'est execute avec succes: on remplit le tablea
			if (list($type,$length)=split("[(]|[)]", $tab['Type'])){
				//Si c'est un varchar, on separe lenght de type avec une expression reg
				if (preg_match("#varchar#",$tab['Type'])){
					$this->tableSql[$tab['Field']]['length'] = $length;
					$this->tableSql[$tab['Field']]['type'] = $type;
				}else  $this->tableSql[$tab['Field']]['type'] = $type;
			}else $this->tableSql[$i]['type'] = $tab['Type'];
			//On transforme les booleens de SQL en booleen classique
			$this->tableSql[$tab['Field']]['null'] = ($tab['Null']=="YES") ? 1:0;
			$this->tableSql[$tab['Field']]['default'] = $tab['Default'];
			$i++;
		}
		return true;
	}


	//Cree un nouveau champ: 'propriete' ou clef 'etrangere' selon le type mentionne.
	function createNewField ($Nom,$type,$Prefixe="") {
		$sql = 'ALTER TABLE `'.$this->Prefix.$this->titre.'` ADD ';
		if ($type == 'propriete') $sql .= $this->writeProperty($Nom,$Prefixe);
		if ($type == 'systeme') $sql .= $this->writeSysProperty($Nom,$Prefixe);
		elseif($type == 'etrangere'){
			$sql .= $this->writeForeignKey($Nom);
		}
		//Si la requete est OK, on renvoie true et un message. Sinon, on renvoie false et une erreur.
		if ($this->executeSql($sql,"MODIF")) return true;
		else{
			$GLOBALS['Systeme']->Error->sendWarningMsg(2,"ERREUR 2:CREATENEWFIELD");
			return false;
		}
	}

	//Cette methode pre-ecrit les requetes SQL au sujet des proprietes
	function writeProperty($Nom,$Prefixe="") {
		if (is_array($Nom)){
			$Tab = $Nom;
			$Nom = $Tab["Nom"];
		}else $Tab=$this->Proprietes[$Nom];
		if ($Prefixe != NULL) $sql= '`'.$Prefixe.'-'.$Nom.'` ';
		else $sql= '`'.$Nom.'` ';
		//Le type et la longueur:
		$sql.= ($Tab['type'] == 'varchar') ? $Tab['type'].'('.(($Tab['length']!="")?$Tab['length']:"255").') ': $Tab['type'].' ';
		//La possibilite d'etre vide:
		if ($Tab['null'] == "false") $sql.='NOT';
		$sql.=' NULL';
		//La valeur par defaut:
		if ($Tab['default'] != NULL&&sizeof(explode("::",$Tab['default']))==1) $sql.= ' default "'.$Tab['default'].'"';
		//Si le type est une reference alors il faut faut faire 3 champs supplementaires
		if ($Tab["special"]=="Reference"){
			//Le type et la longueur:
			$sql.= ',ADD `Module` varchar(50) NULL,ADD `ObjectClass` varchar(50) NULL,ADD `Value` INT NULL';
		}
		return $sql;
	}

	//Cette methode pre-ecrit les requetes SQL au sujet des proprietes
	function writeSysProperty($Nom,$Prefixe="") {
		$Tab=$this->Needed[$Nom];
		$sql= '`'.$Nom.'` ';
		//Le type et la longueur:
		$sql.= $Tab;
		//La valeur par defaut:
		return $sql;
	}

	//Cette methode pre-ecrit les requetes SQL au sujet des clefs secondaires
	function writeForeignKey($Nom) {
		$Tab=$this->Etrangeres[$Nom];
		//ANalyse de data
		$t=explode(",",$Tab["data"]);
		if ($t[1]!="Id"){
			//On recupere le type de la cible
			$K = $GLOBALS["Systeme"]->Modules[$this->Module]->Db->findByTitle($t[0]);
			$P = $GLOBALS["Systeme"]->Modules[$this->Module]->Db->ObjectClass[$K]->Proprietes[$t[1]];
			$P["Nom"] = $Nom;
			$sql = $this->writeProperty($P);
		}else{
			//On leur donne un nom
			$sql= '`'.$Nom.'`';
			//On leur donne un NULL correspondant a leur cardinalites
			$sql.= ($Tab['card'] == "1,1" || $Tab['card'] == "1,n") ? 'INT NOT NULL': 'INT NULL';
		}
		return $sql;
	}

	//Cette methode met a jour les tables MySql, colonne par colonne.
	function alterSql($nom, $type="prop") {
		$sql = 'ALTER TABLE `'.$this->Prefix.$this->titre.'` MODIFY ';
		//Si c'est une clef etrangere, on precise juste son nom
		switch($type)
		{
			case "fkey":
				$sql.= '`'.$nom.'` INT ';
				if ($this->Etrangeres[$nom]['card'] == "1,1") $sql.='NOT';
				$sql.=' NULL';
				break;
			case "prop":
				$sql.= $this->writeProperty($nom);
				break;
			case "sys":
				$sql.= $this->writeSysProperty($nom);
				break;
		}
		if ($this->executeSql($sql,"MODIF")) return true;
		else{
			$GLOBALS['Systeme']->Error->sendWarningMsg(2,"ERREUR 2 :ALTERSQL");
			return false;
		}
	}

	//Methode qui cree les tables SQL correspondants au contenu de la classe.
	function generateSqlTable() {
		$sql  = 'CREATE TABLE IF NOT EXISTS `'.$this->Prefix.$this->titre.'` (';
		$sql.= '`Id` INT NOT NULL AUTO_INCREMENT,';
		$sql.= '`tmsCreate` INT NOT NULL,';
		$sql.= '`userCreate` VARCHAR(30) NOT NULL,';
		$sql.= '`tmsEdit` INT NOT NULL,';
		$sql.= '`userEdit` VARCHAR(30) NOT NULL,';
		$sql.= ' uid int(11) default NULL,';
		$sql.= ' gid int(11) default NULL,';
		$sql.= ' umod int(11) default NULL,';
		$sql.= ' gmod int(11) default NULL,';
		$sql.= ' omod int(11) default NULL,';
		//Puis on insere les proprietes
		foreach ($this->Proprietes as $Key=>$Prop){
			//D'abord le nom
			if (empty($Prop["Ref"])){
				if ($Key!="Id") if ($Flag) $sql.= ' ,';
				if ($Key!="Id") $sql.= $this->writeProperty($Key);
				$Flag = true;
			}
		}
		//Ensuite, on insere les clefs etrangeres
		foreach ($this->Etrangeres as $Key=>$Etr){
			if (in_array($Etr['card'],$this->isShortKey)) {
				if ($Flag) $sql.= ',';
				$sql .= mysqlDriver::writeForeignKey($Key);
				$Flag = true;
			}
		}
		//On insere la clef primaire et on finit la requete SQL
		$sql.= ', UNIQUE (`Id`) )';
		//On execute la requete: si elle s'est bien passe = 1, sinon =0
		if (mysqlDriver::executeSql($sql,"CREATE")) return mysqlDriver::fillTable();
		else{
			$GLOBALS['Systeme']->Error->sendWarningMsg(2,"ERREUR 2 :RENAMESQL");
			return false;
		}
	}


	//Compare les proprietes du tableau avec celles de la table
	function compareProperties() {
		//On charge le tableau qui contient les conversions possibles
		$Langues = $GLOBALS["Systeme"]->Conf->get("GENERAL::LANGUAGE");
		$conversion['varchar'] = 'text';
		$conversion['bool'] = 'int';
		$conversion['int']= 'varchar';
		//On verifie les proprietes systemes
		foreach($this->Needed as $Nom => $Prop){
			if (@!array_key_exists($Nom,$this->tableSql)) {
				//OK
				echo "<li>--#> On cree un nouveau champ $Nom </li>";
				$this->createNewField($Nom, 'systeme');
			}
		}
		foreach($this->Proprietes as $Nom => $Prop){
			if (!empty($Prop["Ref"])) continue;
			//Compteur de changement
			$noChange = 0;
			//Compteur de creation
			if (array_key_exists($Nom,$this->tableSql)) {
				//Le type:
				if ($Prop['type'] == $this->tableSql[$Nom]['type']) $noChange++;
				//La longueur:
				if ($Prop['length'] == $this->tableSql[$Nom]['length']) $noChange++;
				//La valeur par defaut:
				if ($Prop['default'] ==  $this->tableSql[$Nom]['default']) $noChange++;
			}else{
				echo "<li>--##> On cree un nouveau champ $Nom </li>";
				$this->createNewField($Nom, 'propriete');
				die("REFRESH PLEASE ...");
				//return true;
			}
			//Cas du changement de langue
			foreach ($Langues as $Prefixe=>$Langue){
				if ($Prop["special"]=="multi"){
					if (!@array_key_exists($Prefixe."-".$Nom,$this->tableSql)&&$Langue["DEFAULT"]!=1) {
						echo "<li>NEW FIELD $Prefixe-$Nom </li>";
						$this->createNewField($Nom,'propriete',$Prefixe);
					}
				}
			}
			//Si un des noChange n'a pas ete incremente, le champ est mis a jour.
			if ($noChange != 3) {
				$this->alterSql($Nom);
				return true;
			}
		}
		return false;
	}


	//Compare les cles etrangeres du tableau avec celles de la table.
	function compareFKeys(){
		foreach ($this->Etrangeres as $Nom=>$Etr){
			if (!array_key_exists($Nom,$this->tableSql)&&($Etr['card']=="0,1"||$Etr['card']=="1,1")) {
				//Si le champ n'existe pas, on le cree.
				$this->createNewField($Nom,'etrangere');
			}
		}
		return false;
	}

	//----------------------------------------------//
	//	RECURSIVITE INTERVALLAIRE		//
	//----------------------------------------------//

	//Creation des tables d intervalle
	function createIntervalIndex(){
		//ON cree donc une table contenant les bords droits , bords gauche ainsi que l association
		//avec l id de la donnï¿œe
		$sql  = 'CREATE TABLE IF NOT EXISTS `'.$this->Prefix.$this->titre.'-Interval` (';
		$sql.= '`Id` INT NOT NULL ,';
		$sql.= '`Bd` INT NOT NULL ,';
		$sql.= '`Bg` INT NOT NULL )';
		$this->executeSql($sql,"CREATE");
		$this->purgeInterval();
		$this->IndexInterval(0,1);
	}

	//Vide la table d intervalles
	function purgeInterval(){
		$sql='TRUNCATE TABLE `'.$this->Prefix.$this->titre.'-Interval`';
		$this->executeSql($sql,"DELETE");
	}

	//Fonction de reindexation du systeme d intervalle a partir de l association parente
	function IndexInterval($Id,$Bg){
		//On commence par enregistrer le bord gauche
		//----> Bord Gauche ok
		$BordGauche = $Bg;
		$Bg++;
		$Objs=$this->getChildForInterval($Id);
		if (is_array($Objs))foreach ($Objs as $Obj){
			//Pour chaque reponse on relance la methode pour mettre a jour toute la table
			$Bg=$this->IndexInterval($Obj["Id"],$Bg,$Total);
			$Bg++;
		}
		//On enregistre le bord droit
		$this->recordInterval($Id,$BordGauche,$Bg);
		return $Bg;
	}

	//Insere un nouvel index
	function insertIntervalData($Id,$IdParent){
		//Recuperation des informations du parent pour avoir le bord droit
		if ($IdParent=="") $IdParent = 0;
		$sql='SELECT Bd FROM `'.$this->Prefix.$this->titre.'-Interval` WHERE Id='.$IdParent;
		$Result = $this->executeSql($sql,"SELECT_SYS");
		$Bd = $Result[0]["Bd"];
		//ON pousse les bornes droite de 2
		$sql = 'UPDATE `'.$this->Prefix.$this->titre.'-Interval` SET Bd=Bd+2 WHERE Bd >= '.$Bd;
		$this->executeSql($sql,"SELECT_SYS");
		//On pousse egalement le bord gauche de 2
		$sql = 'UPDATE `'.$this->Prefix.$this->titre.'-Interval` SET Bg=Bg+2 WHERE Bg >= '.$Bd;
		$this->executeSql($sql,"SELECT_SYS");
		//ON insere enfin l index
		$sql = 'INSERT INTO `'.$this->Prefix.$this->titre.'-Interval` (Bg,Id,Bd) VALUES ('.$Bd.','.$Id.','.($Bd+1).')';
		$this->executeSql($sql,"SELECT_SYS");
	}

	//Eneleve un index
	function removeIntervalData($Id){
		//Recuperation des informations du parent pour avoir le bord droit
		$sql='SELECT Bg FROM `'.$this->Prefix.$this->titre.'-Interval` WHERE Id='.$Id;
		$Result = $this->executeSql($sql,"SELECT_SYS");
		$Bg = $Result[0]["Bg"];
		//ON supprime les index
		$sql = 'DELETE FROM `'.$this->Prefix.$this->titre.'-Interval` WHERE Id='.$Id;
		$this->executeSql($sql,"SELECT_SYS");
		//ON pousse les bornes droite de 2
		$sql = 'UPDATE `'.$this->Prefix.$this->titre.'-Interval` SET Bg=Bg-2 WHERE Bg >= '.$Bg;
		$this->executeSql($sql,"SELECT_SYS");
		//On pousse egalement le bord gauche de 2
		$sql = 'UPDATE `'.$this->Prefix.$this->titre.'-Interval` SET Bd=Bd-2 WHERE Bd >= '.$Bg;
		$this->executeSql($sql,"SELECT_SYS");
	}

	//Recupere l ensemble des enfants d une donnee
	function getChildForInterval($Id) {
		//On recherche recursivement les categories et on recree l index selon les cardinalites
		foreach ($this->childOf as $Child){
			if ($Child["Titre"]==$this->titre) {
				$Key = $Child;
				$Card = $Child["Card"];
			}
		}
		if ($Card=="0,1"||$Card=="1,1"){
			$Champ = $this->findReflexive();
			//On appelle la table concernï¿œe
			$Data['Table'][0]['Alias'] = "m";
			$Data['Table'][0]['Nom'] = $this->titre;
			$Data['Select'][0]['Nom'] = "m.Id";
			if ($Id==0) {
				$Data['Groupe'][0]['Lien'] = "OR";
				$Data['Groupe'][0]['Condition'][0] = "m.$Champ IS NULL";
				$Data['Groupe'][0]['Condition'][1] = "m.$Champ=0";
			}else{
				$Data['Groupe'][0]['Lien'] = "AND";
				$Data['Groupe'][0]['Condition'][0] = "m.$Champ=$Id";
			}
		}elseif ($Card=="0,n"||$Card=="1,n"){
			//Il faut donc faire une jointure avec la table associative
			//On appelle la table concernï¿œe
			$Data['Table'][0]['Alias'] = "m";
			$Data['Table'][0]['Nom'] = $this->titre;
			$Data['Table'][1]['Alias'] = "j";
			$Data['Table'][1]['Nom'] = $Key["Table"];
			$Data['Select'][0]['Nom'] = "m.Id";
			$Data['Groupe'][0]['Lien'] = "AND";
			if ($Id==0) {
				$Data['Groupe'][0]['Condition'][0] = "j.".$Key["Champ"]." IS NULL";
			}else{
				$Data['Groupe'][0]['Condition'][0] = "j.".$Key["Champ"]."='$Id'";
			}
			$Data['Groupe'][0]['Condition'][0] = "j.".$Key["Champ"]."='$Id'";
			$Data['Groupe'][0]['Condition'][1] = "m.Id=j.".$Key["Titre"];
		}
		$sql = $this->createSql("SELECT_INTERVAL",$Data,$Analyse);
		$resql = $this->executeSql($sql,"SELECT_SYS");
		if (MDB2::isError($resql)) return false;
		$i = 0;
		foreach($resql as $tab){
			$Results[$i]=$tab;
			$Results[$i]["ObjectType"]=$this->titre;
			$i++;
		}
		return $Results;
	}

	//Enregistre d un index d intervalle
	function recordInterval($Id,$Bg,$Bd){
		$sql  = 'INSERT INTO `'.$this->Prefix.$this->titre.'-Interval` SET ';
		if ($Bg!="") $sql .= ' Bg = "'.$Bg.'",';
		if ($Bd!="") $sql .= ' Bd = "'.$Bd.'" ,';
		$sql .= 'Id="'.$Id.'" ';
		$this->executeSql($sql,"UPDATE");
	}

	function verifyIntervalIndex() {return false;}


	//----------------------------------------------//
	// RECHERCHE					//
	//----------------------------------------------//

	//Effectue une recherche et la renvoie a lanalyse
	function DriverSearch($Analyse,$Select,$GroupBy){
		$Data = $this->joinSql($Analyse,$Data);
		$sql  = $this->createSql("SELECT",$Data,$Select);
		$Results=$this->executeSql($sql,"SELECT",$GroupBy);
		return (sizeof($Results)!=0) ? $this->analyzeSearch($Results,"",1) : false;
	}

	function recursivDeleteOldParity($Grp,$Prefixe)
	{
		for ($i=0;$i<count($Grp);$i++)
		{
			$SaveGrp=$Grp[$i]["Condition"]["Groupe"];
			unset($Grp[$i]["Condition"]["Groupe"]);
			foreach ($Grp[$i]["Condition"] as $K=>$C)
			{
				if (strstr($C,$Prefixe)){unset($Grp[$i]["Condition"][$K]);}
			}
			$SaveGrp = $this->recursivDeleteOldParity($SaveGrp,$Prefixe);
			if (count($Grp[$i]["Condition"])==0) unset($Grp[$i]);
			$Grp[$i]["Condition"]["Groupe"] = $SaveGrp;
		}
		return $Grp;
	}

	function joinRecursiv($Tab,$Data,$i) {
		//On ajoute une premiere table d index correspondant
		//$GLOBALS["Systeme"]->Log->log("DEBUG ".$this->isReflexive($Tab[$i]["Nom"]));
		switch ($this->isReflexive($Tab[$i]["Nom"])){
			case "1":
				if ($i>0){
					//Il faut retirer la contrainte de jointure de la paire precedente
					$Gout="";
					$Out=$Data;
					if (is_array($Data["Groupe"]))
					$Data["Groupe"] = $this->recursivDeleteOldParity($Data["Groupe"],$this->getPrefixe($Tab,$i).".");
					/*foreach ($Data["Groupe"] as $Kg=>$G){
						$Cout="";
						$SaveGrp = $G["Condition"]["Groupe"];
						unset($G["Condition"]["Groupe"]);
						if (is_array($G["Condition"]))foreach ($G["Condition"] as $Kc=>$C){
						if (!strstr($C,$this->getPrefixe($Tab,$i)."."))$Cout[] = $C;
						}
						$Gout = $G;
						$Gout["Condition"] = $Cout;
						$Gout["Condition"]["Groupe"] = $SaveGrp;
						$Out["Groupe"][$Kg] = $Gout;
						}*/

					//$Data = $Out;
				}
				$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i]["Nom"];
				$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = $this->getPrefixe($Tab,$i);
				/*				if ($i==0){
					//Si c est le premier , il faut ajouter la table de tri
					$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i]["Nom"];
					$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = $this->getPrefixe($Tab,$i)."t";
					}*/
				//Mise en place des intervalles
				if($i<sizeof($Tab)-1){
					$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i]["Nom"]."-Interval";
					$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = $this->getPrefixe($Tab,$i)."j";
				}
				$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i]["Nom"]."-Interval";
				$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = $this->getPrefixe($Tab,$i)."i";
				$Groupe["Lien"] = "AND";
				if ($Tab[$i-1]["Card"]=="0,n"||$Tab[$i-1]["Card"]=="1,n"){
					$Condition[]=$this->getPrefixe($Tab,$i)."i.Id=".$this->getPrefixe($Tab,($i-1))."t.".$Tab[$i-1]["NomEnfant"];
				}else{
					if ($i==0) $Condition[]=$this->getPrefixe($Tab,$i)."i.Id=0";
					else $Condition[]=$this->getPrefixe($Tab,$i)."i.Id=".$this->getPrefixe($Tab,($i-1)).".Id";
				}
				$Condition[]=$this->getPrefixe($Tab,$i).'j.Id='.$this->getPrefixe($Tab,$i).".Id";
				$Condition[]=$this->getPrefixe($Tab,$i).'i.bd>='.$this->getPrefixe($Tab,$i)."j.bd";
				$Prefs = $this->getPrefixe($Tab,$i);
				$Temp=$Prefs."i.bg";
				$Temp.='<=';
				$Temp.=$Prefs."j.bg";
				$Condition[] = $Temp;
				//$GLOBALS["Systeme"]->Log->log($Temp);
				$Groupe["Condition"]=$Condition;
				$Data["Groupe"][] = $Groupe;
				if (is_array($Data['GroupBy']))foreach ($Data['GroupBy'] as $g)if ($g=="m.Id")$flag=true;
				if (!$flag)$Data['GroupBy'][] = "m.Id";
				break;
			case "2":
				foreach ($this->childOf as $Child) $C = $Child;
				$Data['Table'][0]['Nom'] = $C["Titre"];
				$Data['Table'][0]['Alias'] = "m";
				$Data['Table'][1]['Nom'] = $C["Table"];
				$Data['Table'][1]['Alias'] = "j";
				$i=0;
				$Groupe["Lien"] = "AND";
				$Condition[]="m.Id=j.".$C["Titre"];
				//On ajoute une premiere table d index correspondant
				$Groupe["Condition"]=$Condition;
				$Data["Groupe"][] = $Groupe;
				$Data['Select'][] = Array ("Nom"=>"j.".$C["Titre"]."Id","Alias"=>"ClefReflexive");
				break;
		}
		if (($Tab[$i]["Card"] == "0,1" || $Tab[$i]["Card"] == "1,1")){
			$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i]["Nom"];
			$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = $this->getPrefixe($Tab,$i);
			//-------------------CONDITIONS DE JOINTURE
			$NumGroupe = sizeof($Data["Groupe"]);
			$Data['Groupe'][$NumGroupe]['Lien'] = "AND";
			$Data['Groupe'][$NumGroupe]['Condition'][] = $this->getPrefixe($Tab,$i).".".$Tab[$i]["Target"]."=".$this->getPrefixe($Tab,$i+1).".".$Tab[$i]["Champ"];
		}elseif (($Tab[$i]["Card"] == "0,n" || $Tab[$i]["Card"] == "1,n")){
			//On joint la table de liaison
			$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i]["Table"];
			$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = "j".$i."s";
/*			$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i]["Nom"];
			$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = "j".($i+1)."s";;*/
			$NumGroupe = sizeof($Data["Groupe"]);
			//---------------CONDITIONS DE JOINTURE
			$Data['Groupe'][$NumGroupe]['Lien'] = "AND";
			$Data['Groupe'][$NumGroupe]['Condition'][] = "j".$i.".Id=j$i"."s.".$Tab[$i]["Nom"]."Id";
			$Data['Groupe'][$NumGroupe]['Condition'][] = $this->getPrefixe($Tab,$i+1).".".$Tab[$i]["Target"]."=j$i"."s.".$Tab[$i]["NomEnfant"];
		}
		return $Data;
	}

	function joinStandard($Tab,$Data,$i){
		//On ajoute la table de l objet concernï¿œ
		$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i]["Nom"];
		//Si ce n est pas le premier element alors on fait la jointure avec la paire precedente.
		if (!$Tab[$i]["NomEnfant"]){
			//Si pas de jointure
			if ($Tab[$i]["Out"])$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = "m";
			else $Data["Table"][sizeof($Data["Table"])-1]['Alias'] = "j$i";
			//Gestion de la reflexivitï¿œ
			if ($Tab[$i]["Reflexive"]==1&&$Tab[$i-1]["NomEnfant"]!=$Tab[$i]["Nom"]&&!$Tab[$i]["Recherche"]) {
				//Reflexivite faible
				$NumGroupe = sizeof($Data["Groupe"]);
				$Data['Groupe'][$NumGroupe]['Lien'] = "OR";
				$Data['Groupe'][$NumGroupe]['Condition'][] = $this->getPrefixe($Tab,$i).".".$this->findReflexive()." IS NULL";
				$Data['Groupe'][$NumGroupe]['Condition'][] = $this->getPrefixe($Tab,$i).".".$this->findReflexive()."=''";
				$Data['Groupe'][$NumGroupe]['Condition'][] = $this->getPrefixe($Tab,$i).".".$this->findReflexive()."=0";
			}
		}else{
			//Si jointure
			$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = "j$i";
			//On selectionne l'id de la requete pour l'historique
			$Data['Select'][] = Array ("Nom"=>"j$i.Id","Alias"=>"__Liaison_J$i");
			$Data['Select'][] = Array ("Valeur"=>$Tab[$i]["Nom"],"Alias"=>"__Liaison_titre_J$i");
			if (($Tab[$i]["Card"] == "0,1" || $Tab[$i]["Card"] == "1,1")){
				//-------------------CONDITIONS DE JOINTURE
				$NumGroupe = sizeof($Data["Groupe"]);
				$Data['Groupe'][$NumGroupe]['Lien'] = "AND";
				$Data['Groupe'][$NumGroupe]['Condition'][] = $this->getPrefixe($Tab,$i).".".$Tab[$i]["Target"]."=".$this->getPrefixe($Tab,$i+1).".".$Tab[$i]["Champ"];
			}else{
				//On joint la table de liaison
				$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i]["Table"];
				$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = "j".$i."t";
				$NumGroupe = sizeof($Data["Groupe"]);
				//---------------CONDITIONS DE JOINTURE
				$Data['Groupe'][$NumGroupe]['Lien'] = "AND";
				$Data['Groupe'][$NumGroupe]['Condition'][] = "j$i.Id=j$i"."t.".$Tab[$i]["Nom"]."Id";
				$Data['Groupe'][$NumGroupe]['Condition'][] = $this->getPrefixe($Tab,$i+1).".".$Tab[$i]["Target"]."=j$i"."t.".$Tab[$i]["NomEnfant"];
			}
		}
		return $Data;
	}

	function joinParentRecursiv($Tab,$Data,$i){
		//Objet Enfant portant les filtres
		$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i+2]["Nom"];
		$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = "j".($i+2)."p";
		//Objet ciblé
		$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i]["Nom"];
		$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = "m";
		switch ($Tab[$i+1]["Card"]) {
			case "0,n":
			case "1,n":
				//Table de liaison entre l objet enfant et l objet parent
				$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i+1]["Table"];
				$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = "j".($i+1)."t";
				//Liaison entre intervalle de comparaison et la table de liaison
				$Data['Groupe'][$NumGroupe]['Condition'][] = "j".$i."i.Id=j".($i+1)."t.".$Tab[$i+1]["Parent"]."Id";
				$Data['Groupe'][$NumGroupe]['Condition'][] = "j".($i+2)."p.Id=j".($i+1)."t.".$Tab[$i+1]["Champ"];
				break;
			case "0,1":
			case "1,1":
				//Liaison entre intervalle de comparaison et la table de liaison
				$Data['Groupe'][$NumGroupe]['Condition'][] = "j".$i."i.Id=j".($i+2)."p.".$Tab[$i+1]["Parent"]."Id";
				break;
		}
		switch ($Tab[$i]["Card"]) {
			case "0,1":
			case "1,1":
				//Table d intervalle  l objet parent
				$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i]["Nom"]."-Interval";
				$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = "j".$i."i";
				//Mise en place du filtre
				$NumGroupe = sizeof($Data["Groupe"]);
				$Data['Groupe'][$NumGroupe]['Lien'] = "AND";
				$Data['Groupe'][$NumGroupe]['Condition'][] = "j".($i+2)."p.Id = ".$Tab[$i+2]["Recherche"];
				//Liaison entre intervalle et objet ciblé
				$Data['Groupe'][$NumGroupe]['Condition'][] = "m.Id=mj.Id";
				//Conditions intervallaires
				$Groupe["Lien"] = "AND";
				$Condition[]=$this->getPrefixe($Tab,$i)."i.bd<=mj.bd";
				$Condition[]=$this->getPrefixe($Tab,$i)."i.bg>=mj.bg";
				$Groupe["Condition"]=$Condition;
				$Data["Groupe"][] = $Groupe;
				if (is_array($Data['GroupBy']))foreach ($Data['GroupBy'] as $g)if ($g=="m.Id")$flag=true;
				if (!$flag)$Data['GroupBy'][] = "m.Id";
				break;
		}
		return $Data;
	}
	function joinParent($Tab,$Data,$i){
		//On ajoute la table de l objet concernï¿œ
		//O ajoute la table de filtre
		$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i+1]["Nom"];
		$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = "j".($i+1)."p";
		//Table resultat
		$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i]["Parent"];
		$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = "m";
		if (($Tab[$i]["Card"] == "0,1" || $Tab[$i]["Card"] == "1,1")){
			//-------------------CONDITIONS DE RECHERCHE
			$Temp = $this->whereSql($Tab[$i+1],$Data,"j".($i+1)."p");
			if (is_array($Temp['Groupe']))foreach ($Temp['Groupe'] as $G){
				$Data['Groupe'][] = $G;
			}
			$Data['Suffixe'] = $Temp['Suffixe'];
			$NumGroupe = sizeof($Data["Groupe"]);
			$Data['Groupe'][$NumGroupe]['Lien'] = "AND";
			$Data['Groupe'][$NumGroupe]['Condition'][] = "j".($i+1)."p.".$Tab[$i]["Champ"]."=m.".$Tab[$i]["Target"];
			//-------------------CONDITIONS DE JOINTURE
			$NumGroupe = sizeof($Data["Groupe"]);
			//$Data['Groupe'][$NumGroupe]['Condition'][] = $Temp['Groupe'][0]['Condition'][0];
		}else{
			//On joint la table de liaison
			$Data["Table"][sizeof($Data["Table"])]['Nom'] = $Tab[$i]["Table"];
			$Data["Table"][sizeof($Data["Table"])-1]['Alias'] = "j".$i."t";
			$Temp = $this->whereSql($Tab[$i+1],Array(),"j".($i+1)."p");
			if (is_array($Temp['Groupe']))foreach ($Temp['Groupe'] as $G){
				$Data['Groupe'][] = $G;
			}
			$Data['Suffixe'] = $Temp['Suffixe'];
			$NumGroupe = sizeof($Data["Groupe"]);
			$Data['Groupe'][$NumGroupe]['Lien'] = "AND";
			//---------------CONDITIONS DE JOINTURE
			$Data['Groupe'][$NumGroupe]['Lien'] = "AND";
			$Data['Groupe'][$NumGroupe]['Condition'][] = "j".($i+1)."p.Id=j$i"."t.".$Tab[$i]["NomEnfant"];
			$Data['Groupe'][$NumGroupe]['Condition'][] = "m.".$Tab[$i]["Target"]."=j$i"."t.".$Tab[$i]["Parent"]."Id";
			if (is_array($Data['GroupBy']))foreach ($Data['GroupBy'] as $g)if ($g=="m.Id")$flag=true;
			if (!$flag)$Data['GroupBy'][] = "m.Id";
		}
		if (is_array($Tab[$i+2])){
			//Ajout d un filtre sur la sortie
			$Temp = $this->whereSql($Tab[$i+2],$Data,"m");
			$Data['Groupe'][$NumGroupe]['Condition'][] = $Temp['Groupe'][1]['Condition'][0];
			$Data['Suffixe'] = $Temp['Suffixe'];
		}
		return $Data;
	}

	//Definit les prefixe de table en fonction de l emplacement dans le tableau d analyse
	function getPrefixe($Tab,$i){
		return ($i==sizeof($Tab)-1||$Tab[$i]["Parent"])?"m":"j".$i;
	}
	//Definit les prefixe de table en fonction de l emplacement dans le tableau d analyse
	function getTableAssoc($P,$C){
		return ($i==sizeof($Tab)-1)?"m":"j".$i;
	}

	//Cree les conditions de jointures necessaires dans une requete
	function joinSql($Tab,$Data){
		//On boucle sur les objets precedents
		$var  = (sizeof($Tab)>MAIN_DB_RECURSIV_LIMIT&&MAIN_DB_RECURSIV_LIMIT)?sizeof($Tab)-1-MAIN_DB_RECURSIV_LIMIT:0;
		for ($i=$var;$i<sizeof($Tab);$i++){
			if ($Tab[$i+1]["Parent"]==$Tab[$i]["Nom"]&&$Tab[$i]["Recherche"]=="*") {
				$Data = $this->joinParentRecursiv($Tab,$Data,$i);
				$Data["Special"] = "RECURSIV";
				$i++;
				$i++;
			}elseif ($Tab[$i]["Parent"]) {
				$Data = $this->joinParent($Tab,$Data,$i);
				$i = sizeof($Tab)-1;
			}elseif ($Tab[$i]["Recherche"]=="*") {
				//RECURSIVE
				$Data = $this->joinRecursiv($Tab,$Data,$i);
				$Data["Special"] = "RECURSIV";
			}else{
				//CHAINE
				$Data = $this->joinStandard($Tab,$Data,$i);
				$Data = $this->whereSql($Tab[$i],$Data,$this->getPrefixe($Tab,$i));
			}
		}
		return $Data;
	}



	function multiConditions($c,$Tab,$prefixe)
	{
		preg_match("#(.*)([=!+<>~]{2})(.*)#",$c,$Out);
		if (sizeof($Out)<2)preg_match("#(.*)([=!+<>~]{1})(.*)#",$c,$Out);
		$T = explode(".",$Out[1]);
		if (sizeof($T)>1)
		  {$Pref=$T[0].".";$Out[1] = $T[1];}
		else $Pref=$prefixe.".";
		switch ($Out[2]){
			case "=":
			case ">":
			case "<":
			case "<=":
			case ">=":
			case "!=":
				if (is_numeric($Out[3])||$Out[3]=="NULL") $Data['Condition'][] = "$Pref".$Out[1]."".$Out[2]."".$Out[3]."";
				else $Data['Condition'][] = "$Pref`".$this->langProp($Out[1])."`".$Out[2]."'".$Out[3]."'";
				$Made=1;
				$Data["Lien"] = "AND";
				break;
		        case "><":
            			$Fourchette = explode("-->",$Out[3]);
				$Data['Condition'][] = "$Pref`".$Out[1]."`>=".$Fourchette[0];
				$Data['Condition'][] = "$Pref`".$Out[1]."`<=".$Fourchette[1];
				$Made=1;
				$Data['Lien']="AND";
				break;
		        case "!!":
				$Data['Condition'][] = "$Pref`".$Out[1]."` IS NULL";
				$Made=1;
				$Data["Lien"] = "AND";
		                break;
			case "~":
				$Data['Lien'] = "OR";
				//Suppression des pluriels
				//$c = preg_replace("#(.*)(s|e)$#","$1",$Out[3]);
				$mc= $Out[3];
				if ($Out[1]!=""){
					$Rt = explode(" ",$mc);
					if (sizeof($Rt)>1){
						//Si il y a plusierus mots clefs alors on fait une recherche avec select imbrique et exacte.
						//Recherche d'espaces
						foreach ($Rt as $t) {if ($g)$likein.=",";else $g=true;$likein .= "'$t'";}
						$Data['Condition'][] = "$Pref".$Out[1]." IN ($likein)";
						$Data['Suffixe'][] = "having count(*) >= ".sizeof($Rt);
					}else{
						//si il y a qu'u mot clef alors on fait une recherche floue
						$Data['Condition'][] = "$Pref".$Out[1]." LIKE '".$mc."%'";
					}
				}else{
					$Type="string";
					$IdObjClass =$GLOBALS["Systeme"]->Modules[$this->Module]->Db->findByTitle($Tab["Nom"]);
					$Obj = $GLOBALS["Systeme"]->Modules[$this->Module]->Db->ObjectClass[$IdObjClass];
					foreach ($Obj->Cibles as $Nom=>$sOrder){
						if ($Obj->getPropType($Nom)==$Type) {
							//Gestion des langues
							$PropName = $this->langProp($Nom,$Type);
							$Data['Condition'][] ="$Pref".$PropName." LIKE \"%".$mc."%\"";
						}
					}
				}
				$Made=1;
				break;
			default:
				$Made=0;
				break;
		}
		if (is_numeric($c)&&!$Made) {
			//IntSearch
			$Data['Condition'][] = "$prefixe.Id=".$c."";
		}elseif (!$Made){
			//StringSearch
			$Type="string";
			$Data['Lien'] = "AND";
			$IdObjClass = $GLOBALS["Systeme"]->Modules[$this->Module]->Db->findByTitle($Tab["Nom"]);
			$Obj = $GLOBALS["Systeme"]->Modules[$this->Module]->Db->ObjectClass[$IdObjClass];
			$imbriqSql="$prefixe.Id= (SELECT Id FROM `".$this->Prefix.$Obj->titre."` WHERE ";
			foreach ($Obj->Cibles as $Nom=>$sOrder){
				if ($Obj->getPropType($Nom)==$Type) {
					//Gestion des langues
					$PropName = $this->langProp($Nom,$Type);
					if ($f) $imbriqSql.="OR";else $f=true;
					$imbriqSql.= "(`".$PropName."` = \"$c\")";
					if (AUTO_COMPLETE_LANG&&!$GLOBALS["Systeme"]->User->Admin&&$Obj->Proprietes[$Nom]["special"]=="multi"){
						foreach ($GLOBALS["Systeme"]->Conf->get("GENERAL::LANGUAGE") as $Key=>$Lang) {
							if ($GLOBALS["Systeme"]->DefaultLanguage!=$Lang["TITLE"]){
								if ($f) $imbriqSql.="OR";else $f=true;
								if ($Lang["DEFAULT"]!=1){
									$imbriqSql.= "(`".$Key."-".$Nom."` = \"$c\")";
								}else $imbriqSql.= "(`".$Nom."` = \"$c\")";
							}
						}
					}
				}
			}
			$imbriqSql.="LIMIT 0,1)";
			//echo "--> REQUETE IMBRIQUEE => ".$imbriqSql."\r\n";
			$Data['Condition'][] =$imbriqSql;
			/*$Type="string";
			 $Data['Lien'] = "OR";
			 $IdObjClass = $GLOBALS["Systeme"]->Modules[$this->Module]->Db->findByTitle($Tab["Nom"]);
			 $Obj = $GLOBALS["Systeme"]->Modules[$this->Module]->Db->ObjectClass[$IdObjClass];
			 foreach ($Obj->Cibles as $Nom=>$sOrder){
				if ($Obj->getPropType($Nom)==$Type) {
				//Gestion des langues
				$PropName = $this->langProp($Nom,$Type);
				$Data['Condition'][] ="$prefixe.".$PropName." = \"$c\"";
				}
				}*/

		}
		return $Data;
	}

	function getMultiSearch($Tab,$Data,$Rech,$prefixe)
	{
		/*On créé un tableau en découpant chaque (!!) et en notant son parent, son départ, son arrivée, et sa profondeur */
		$TRech = $Rech;$brackets = Array();
		$nump = 0;$prof = $maxprof = 1;
		$lastWithChilds[]=0;
		$brackets[0] = Array("prof"=>0,"opened"=>0,"closed"=>strlen($Rech));
		while (strpos($TRech,'(!') !== false || strpos($TRech,'!)') !== false)
		{
			$nextOpen = strpos($TRech,'(!');
			$nextClose = strpos($TRech,'!)');
			//Si le plus proche est une ouverture
			if ($nextOpen!== false&&($nextClose>$nextOpen||$nextClose===false))
			{
				$brackets[++$nump]["opened"]=$truePos+$nextOpen+2;
				$brackets[$nump]["prof"]=$prof++;
				if ($lastDone=="o") $lastWithChilds[] = $nump-1;
				$brackets[$nump]["parent"] = $lastWithChilds[count($lastWithChilds)-1];
				$brackets[$nump]["lwc"] = $lastWithChilds;
				$TRech = substr($TRech,$nextOpen+2);
				$truePos = $truePos+$nextOpen+2;
				$lastDone = "o";
				if ($maxprof<$prof) $maxprof = $prof;
			}
			//Si le plus proche est une fermeture
			if ($nextClose!== false&&($nextOpen>$nextClose||$nextOpen===false))
			{
				$Index = 0;
				foreach(array_reverse($brackets,true) as $I=>$V)
				{
					if ($Index==0&&empty($V["closed"])) $Index = $I;
				}
				$brackets[$Index]["closed"]=$truePos+$nextClose;
				$TRech = substr($TRech,$nextClose+2);
				$truePos = $truePos+$nextClose+2;
				$prof--;
				if ($lastDone=="c")
				{
					unset($lastWithChilds[count($lastWithChilds)-1]);
				}
				$lastDone = "c";
			}
		}
		/*On range le tableau pour le rendre un peu recursif*/
		for ($j=$maxprof;$j>=0;$j--)
		{
			foreach ($brackets as $K=>&$brak)
			{
				if ($brak["prof"]==$j)
				{
					$FullCondition = substr($Rech,$brak["opened"],$brak["closed"]-$brak["opened"]);
					$FullCondition = preg_replace("#(\(\!.*\!\))#","",$FullCondition);
					$brak["Lien"] = (strpos($FullCondition,"+")) ? "OR":"AND";
					$Conditions = ($brak["Lien"]=="OR") ? explode("+",$FullCondition):explode("&",$FullCondition);
					foreach ($Conditions as $C)
					{
						if (!empty($C)){
							$tempi = $this->multiConditions($C,$Tab,$prefixe);
							if (is_array($tempi["Suffixe"])) $Data["Suffixe"] = $tempi["Suffixe"];
							$brak["Condition"]["Groupe"][] =  $tempi;
						}
					}
					unset($brak["opened"]);
					unset($brak["closed"]);
					unset($brak["lwc"]);
					unset($brak["prof"]);
					if ($j>0)
					{
						$par = $brak["parent"];
						unset($brak["parent"]);
						$brackets[$par]["Condition"]["Groupe"][] = $brackets[$K];
						unset($brackets[$K]);
					}
				}
			}
		}
		$Data["Groupe"][count($Data["Groupe"])] = $brackets[0];
		return $Data;
	}

	function whereSql($Tab,$Data,$prefixe) {

		if (!empty($Tab["Recherche"])) $Data = $this->getMultiSearch($Tab,$Data,$Tab["Recherche"],$prefixe);
		// 		if ($this->titre=="Produit")print_r($Data);
		return $Data;
	}

	/*Fonction récursive:
	 * Créé une requete a partir d'un groupe de conditions
	 * Condition d'arret : Tab[Condition][Groupe].length = 0
	 * Parametre : Tab::tableau
	 * Retourne : ::String
	 */
	function writeConditions($Tab){
		$Grps = $Tab["Condition"]["Groupe"];
		unset($Tab["Condition"]["Groupe"]);
		if (empty($Tab["Lien"])) $Tab["Lien"]="AND";
		$sqlCond = "(";
		$queryStarted=false;
		for ($i=0;$i<count($Tab["Condition"]);$i++){
			if ($i>0) $sqlCond.= " ".$Tab["Lien"]." ";
			$sqlCond.= "(".$Tab["Condition"][$i].")";
			$queryStarted=true;
		}
		for ($i=0;$i<count($Grps);$i++){
			if ($i>0||$queryStarted) $sqlCond.= " ".$Tab["Lien"]." ";
			$sqlCond.= $this->writeConditions($Grps[$i]);
		}
		$sqlCond .= ")";
		return $sqlCond;
	}

	//Constructeur magique de recherche en fonction du tableau d analyse
	function createSql($Type,$Data,$Select=""){
		//Ajout des parametres principaux
		if (!$Select) {
			$sql='SELECT m.Id,m.userCreate,m.tmsCreate,m.tmsEdit,m.userEdit,m.uid,m.gid,m.umod,m.gmod,m.omod';
			foreach ($this->Proprietes as $Key=>$Prop){
				//Priorites de langage
				if (array_key_exists($Key,$this->Proprietes)) $Special = $this->Proprietes[$Key]["special"];
				if (!empty($Prop["Ref"])) $sql.=",r".$Prop["Ref_Level"].".$Key";
				elseif ($Special=="multi"&&$GLOBALS["Systeme"]->User->Admin){
					$sql.=",m.`".$this->langProp($Key)."` as `".$Key."`";
					foreach ($GLOBALS["Systeme"]->Conf->get("GENERAL::LANGUAGE") as $Cod=>$Lang) {
						if (!$Lang["DEFAULT"]) $sql.=",m.`".$Cod."-".$Key."`";
					}
				}elseif ($Special=="multi"&&AUTO_COMPLETE_LANG&&$GLOBALS["Systeme"]->LangageDefaut!=$GLOBALS["Systeme"]->DefaultLanguage){
					$sql.=",m.`".$this->langProp($Key)."` as `".$Key."`";
					foreach ($GLOBALS["Systeme"]->Conf->get("GENERAL::LANGUAGE") as $Cod=>$Lang) {
						if ($Lang["DEFAULT"]) $sql.=",m.`".$Key."`as `$Cod-".$Key."`";
					}
				}else $sql.=",m.`".$this->langProp($Key)."` as `".$Key."`";
			}
			
			//Ajout des champs Select optionnels
			if(is_array($Data['Select'])) {
				foreach ($Data['Select'] as $Selection){
					if (!empty($Selection['Nom'])){
						$sql.=",".$Selection['Nom']." as `".$Selection['Alias'].'`';
					}else{
						$sql.=",'".$Selection['Valeur']."' as `".$Selection['Alias'].'`';
					}
				}
			}

			if ($this->isReflexive()==1){
				$sql.=",m.".$this->findReflexive()." as `ClefReflexive`";

			}
			if ($this->isReflexive()&&$Type!="SELECT_INTERVAL"){ //&&$Data["Special"]=="RECURSIV"){
				$sql.=",mj.Bd as `Bd`,mj.Bg as `Bg`";
				$Table["Nom"] = $this->titre."-Interval";
				$Table["Alias"] = "mj";
				$Data["Table"][] = $Table;
				$Data['Groupe'][]['Condition'][] ="mj.Id = m.Id";
			}
		}else $sql = 'SELECT '.$Select;
		//Ajout des tables et de leur alias
		$sql.=" FROM ";
		foreach ($Data['Table'] as $Table) {
			if ($Flag) $sql.=",";$Flag=true;
			$Prefix= ($Table['Option']=="NO_PREFIX") ? "":$this->Prefix;
			$sql.="`".$Prefix.$Table['Nom'].'` as `'.$Table['Alias'].'`';
			//Gestion des Joins
			if (is_array($Table['Join'])) foreach ($Table['Join'] as $Jo){
				$Prefix= ($Jo['Option']=="NO_PREFIX") ? "":$this->Prefix;
				$sql.=" ".$Jo['Side']." JOIN `".$Prefix.$Jo['Table'].'` as `'.$Jo['Alias'].'` ON ('.$Jo['On'].')';
			}
		}
		$r=0;
		$sql.= ' WHERE 1';
		//Gestion des droits
		if (!empty($GLOBALS["Systeme"]->User->Id) && !$GLOBALS["Systeme"]->User->Admin && $this->titre!="Connexion"){
			$GroupeDroits = Array("Lien"=>"OR");
			$GroupeDroits["Condition"][] = "m.omod>=3";
			$GGroupeDroits = Array ("Lien"=>"AND");
			$GGroupeDroits["Condition"][] = "m.umod>=3";
			$GGroupeDroits["Condition"][] = "m.uid=".$GLOBALS["Systeme"]->User->Id;
			$GroupeDroits["Condition"]["Groupe"][] = $GGroupeDroits;
			if (is_array($GLOBALS["Systeme"]->User->Groups)) foreach ($GLOBALS["Systeme"]->User->Groups as $Grp){
				$GGroupeDroits = Array ("Lien"=>"AND");
				$GGroupeDroits["Condition"][] = "m.gmod>=3";
				$GGroupeDroits["Condition"][] = "m.gid=".$Grp->Id;
				$GroupeDroits["Condition"]["Groupe"][] = $GGroupeDroits;
			}
			$Data["Groupe"][] = $GroupeDroits;
		}
		//Ajout des conditions et des groupes de conditions
		$Linking = " AND ";
		if (is_array($Data['Groupe'])){
			foreach ($Data['Groupe'] as $Grp){
				$Flag_2 = false;
				$NString = $this->writeConditions($Grp);
				if ($NString!=""&&$NString!="()") $sql.=$Linking." (".$NString.") ";
			}
		}
		//Gestion des GROUP BY
		if (is_array($Data['GroupBy'])&&($Select==""||is_array($Data['Suffixe']))){
			$sql.=" GROUP BY ";
			foreach ($Data['GroupBy'] as $Group){
				
				$sql.= "$Flag2 $Group";
				$Flag_2 = ",";
			}
		}
		if (is_array($Data['Suffixe'])){
			foreach ($Data['Suffixe'] as $Group){
				$sql.= "$Flag2 $Group ";
			}
		}
		//echo $sql;
		return $sql;
	}

	/* Cette fonction range et classe dans un tableau les donnees trouvees.
	 Renvoi: le tableau de resultat.
	 Parametres: les donnees trouvees dans la base de donnees, la recherche effectuee*/
	function analyzeSearch($Donnees, $Recherche) {
		$Resultat= Array(); $compteur=0;
		//On procede au calcul de la note que l'on enregistre, avec le reste, dans le tableau final
		foreach ($Donnees as $Enregistrement){
			if (!is_array($Enregistrement)) continue;
			$sOrder = $totalCibles+1;
			$Resultat[$compteur] = $Enregistrement;
			$Resultat[$compteur]['ObjectType'] = $this->titre;
			$Resultat[$compteur]['note'] = 10;
			$compteur++;
		}
		return $Resultat;
	}



	//----------------------------------------------//
	// UTILITAIRES					//
	//----------------------------------------------//
	//Selon le type de la propriete et la langue en vigueur il ajoute le prefixe de langue ou pas
	function langProp($Name) {
		// 		print_r($this->Proprietes);
		//print_r($this->Proprietes[$Name]);
		//echo "$Name $Special \r\n";
		if (array_key_exists($Name,$this->Proprietes)){
			$Special = $this->Proprietes[$Name]["special"];
		}
		$Prefixe = $GLOBALS["Systeme"]->Language[$GLOBALS["Systeme"]->DefaultLanguage];
		$isNotDefault = $GLOBALS["Systeme"]->DefaultLanguage!=$GLOBALS["Systeme"]->LangageDefaut;
		//echo "$isNotDefault\r\n";
		if ($isNotDefault && !$GLOBALS["Systeme"]->User->Admin && $Special=="multi") $Name= "".$Prefixe."-".$Name;
		//echo $GLOBALS["Systeme"]->User->Admin." $Special $Prefixe - $Name\r\n";
		return $Name;
	}


	//----------------------------------------------//
	// INSERTION					//
	//----------------------------------------------//
	//Insere un nouvel objet ou met a jour un ancien selon la presence de lid
	function insertObject($Update=0){
		if ($this->newProperties['Id']==NULL) {
			foreach ($this->newProperties as $NomProp=>$ValeurProp){
				if($Flag) {$Noms.=",";$Valeurs.=",";$RefWhere.=" AND ";}
				$Noms.= '`'.$NomProp.'`';
				$Valeurs.= '\''.addslashes($ValeurProp).'\'';
				if ($NomProp!="Id")$RefWhere .= '(`'.$NomProp.'` = \''.addslashes($ValeurProp).'\' )';
				$Flag=true;
			}
			//On construit la requete SQL
			$sql = 'INSERT INTO `'.$this->Prefix.$this->titre.'` ('.$Noms.') VALUES ('.$Valeurs.')';
			//GESTION DES INTERVALLES
			if ($this->isReflexive()==1){
				//Alors il faut mettre l index intervallaire a jour
				$Parent = $this->newProperties[$this->findReflexive()];
			}
		}else{
			foreach ($this->newProperties as $NomProp=>$ValeurProp){
				if ($Update=="1") {
					if($Flag) $Requete.=" , ";
					$Requete.= "`$NomProp`='".addslashes($ValeurProp)."'";
				}else{
					if($Flag) {$Noms.=",";$Valeurs.=",";}
					$Noms.= '`'.$NomProp.'`';
					$Valeurs.= '\''.addslashes($ValeurProp).'\'';
				}
				$Flag=true;
			}
			//On construit la requete SQL
			if ($Update==1)$sql = 'UPDATE `'.$this->Prefix.$this->titre.'` SET '.$Requete.' WHERE `Id`='.$this->newProperties['Id'];
			else $sql = 'REPLACE INTO `'.$this->Prefix.$this->titre.'` ('.$Noms.') VALUES ('.$Valeurs.')';
			//			echo $sql;
			//GESTION DES INTERVALLES
			if ($this->isReflexive()){
				//Alors il faut mettre l index intervallaire a jour
				$Parent = $this->newProperties[$this->findReflexive()];
			}
		}
		$this->executeSql($sql,"UPDATE");
		//GESTION DES INTERVALLES
		if ($this->isReflexive()&&($this->findReflexiveCard()=="0,1"||$this->findReflexiveCard()=="1,1")) {
			//On recupere l id de l elemnt inserï¿œ
			$Id = $GLOBALS["Systeme"]->Db[$this->Bdd]->lastInsertID();
			//On ajoute l element a lindex intervallaire
			$this->insertIntervalData($Id,$Parent);
		}
		return true;
	}

	//----------------------------------------------//
	// MODFICATION					//
	//----------------------------------------------//
	//Modifie les droits
	function changeRights($Id,$Ui="",$Gi="",$Um="",$Gm="",$Om="")	{
		$sql = "UPDATE `".$this->Prefix.$this->titre."` SET ";
		$sql.="uid=$Ui,gid=$Gi,umod=$Um,omod=$Om,gmod=$Gm WHERE Id=$Id";
		$this->executeSql($sql,"UPDATE");
		return true;
	}

	//Ajoute ou met a jour une association
	function insertKey($Tab,$Id,$Type){
		$TabFields = $this->AddNeededFields('',"ASSOC");
		if (is_array($this->childOf)) foreach ($this->childOf as $Child) {
			if ($Child["Titre"]==$Tab["Titre"]) $C = $Child;
		}
		//Cas d'une clef reflexive
		if ($Tab['Titre']==$this->titre&&($C["Card"]=="0,n"||$C["Card"]=="1,n")) {
			if (!array_key_exists('Id',$Tab)) $Tab['Id'] = $Tab['NouvelId'];
			$sql = "INSERT INTO `".$this->Prefix.$C["Table"]."` SET ";
			foreach ($TabFields as $Nom=>$Valeur){
				if ($Nom!="tmsCreate"||$Nom!="userCreate") $sql.=$Nom."=".$Valeur.", ";
			}
			if ($Tab["Id"]!=""&&$Tab["Id"]!=0) $sql.= "`".$C['Titre']."Id`=".$Tab['Id'].', ';
			else $sql.= "`".$C['Titre']."Id`=NULL, ";
			$sql.="`".$C["Champ"]."`=".$Id;
			return $this->executeSql($sql,"UPDATE");
		}
		$Card = $this->findKey($Tab['Fkey'],'parent','Card');
		if (!$Card) return false;
		//Cas d'une clef secondaire longue
		if (in_array($Card,$this->isLongKey)){
			if (array_key_exists("AncienId",$Tab)){
				//C'est une modif
				$NumAssoc = substr($Tab['numAssoc'],1,strlen($Tab['numAssoc']));
				$sql = "UPDATE `".$this->Prefix.$Tab['Table']."` SET ";
				foreach ($TabFields as $Nom=>$Valeur){
					if ($Nom!="tmsCreate"||$Nom!="userCreate") $sql.=$Nom."=".$Valeur.", ";
				}
				$sql.= $Tab['Fkey']."Id=".$Tab['Id'].', ';
				$sql.= $this->titre."=".$Id;
				$sql.= ' WHERE Id='.$NumAssoc;
			}else{
				$sql = "SELECT * FROM `".$this->Prefix.$C["Table"]."` WHERE `".$this->titre."`=$Id AND ";
				if ($Tab["Id"]!="")$sql.= "`".$Tab['Titre']."Id`=".$Tab['Id'];
				else $sql.="`".$Tab['Fkey']."Id` IS NULL";
				$result = $this->executeSql($sql,"SELECT_SYS");
				if (sizeof($result)) return false;
				if (!array_key_exists('Id',$Tab)) $Tab['Id'] = $Tab['Id'];
				//C'est une insertion
				$sql =  "INSERT INTO `".$this->Prefix.$C['Table']."`  SET ";
				$TabFields = $this->AddNeededFields('','ASSOC');
				foreach ($TabFields as $Nom=>$Valeur){
					if ($Nom!="tmsCreate"||$Nom!="userCreate") $sql.=$Nom."=".$Valeur.", ";
				}
				if ($Tab["Id"]!=""&&$Tab["Id"]!=0) $sql.= "`".$C['Titre']."Id`=".$Tab['Id'].', ';
				else $sql.= "`".$C['Titre']."Id`=NULL, ";
				$sql.= "`".$this->titre."`=".$Id;
			}
		}
		if (in_array($Card,$this->isShortKey)){
			$sql = "UPDATE `".$this->Prefix.$this->titre."` SET ";
			foreach ($TabFields as $Nom=>$Valeur){
				if ($Nom!="tmsCreate"||$Nom!="userCreate") $sql.=$Nom."=".$Valeur.", ";
			}
			$NomChamp = $this->findKey($Tab['Titre'],'parent');
			if ($Tab['Id']!=""&&$Tab['Id']!=0) $sql.=$NomChamp."=".$Tab['Id'];
			else $sql.=$NomChamp." = NULL";
			$sql.= ' WHERE Id='.$Id;
		}
		return $this->executeSql($sql,"UPDATE");
	}


	//----------------------------------------------//
	// SUPPRESSION					//
	//----------------------------------------------//
	//Detruit un objet et toutes les associations qu-il comprend
	function DriverErase($Id){
		$sql="DELETE FROM `".$this->Prefix.$this->titre."` WHERE Id=\"".$Id."\"";
		$Flag = $this->executeSql($sql,"DELETE");
		if (is_array($this->childOf)) foreach($this->childOf as $Assoc){
			$Flag=$this->EraseTableAssociation($Id,"c",$Assoc);
		}
		if (is_array($this->parentOf)) foreach($this->parentOf as $Assoc) {
			$Flag=$this->EraseTableAssociation($Id,"p",$Assoc);
		}
		if ($this->isReflexive()&&($this->findReflexiveCard()=="0,1"||$this->findReflexiveCard()=="1,1")){
			$this->removeIntervalData($Id);
		}
		return $Flag;
	}

	//Detruit toutes les associations vers Id dans la tqble
	function EraseTableAssociation($Id,$Type,$Assoc){
		//Pour les card n1, seul les parents sont concernes
		$sql="";
		if (in_array($Assoc['Card'],$this->isShortKey) && $Type=="p"){
			if ($this->titre==$Assoc['Titre']) $sql="UPDATE `".$this->Prefix.$this->titre."` SET `".$Assoc['Champ']."`='' WHERE `".$Assoc['Champ']."`=\"".$Id."\"";
			else $sql="UPDATE `".$this->Prefix.$Assoc['Titre']."` SET `".$Assoc['Champ']."`='' WHERE `".$Assoc['Champ']."`=\"".$Id."\"";
		}
		if (in_array($Assoc['Card'],$this->isLongKey)){
			if ($Type=="c"){
				$sql="DELETE FROM `".$this->Prefix.$Assoc['Table']."` WHERE `".$this->titre."`=\"".$Id."\"";
			}
			elseif ($Type=="p"){
				$sql="DELETE FROM `".$this->Prefix.$Assoc['Table']."` WHERE `".$Assoc['Champ']."`=\"".$Id."\"";
			}
		}
		if ($sql!="") return $this->executeSql($sql,"DELETE");
		else return true;
	}


	//Supprime une association
	function EraseAssociation($currentId,$beforeDs,$beforeId){
		foreach($this->childOf as $Parent){
			if ($Parent['Titre']==$beforeDs) $Relative = $Parent;
		}
		//On efface l'association de this vers X ou X vers this dans une table
		if (in_array($Relative['Card'],$this->isShortKey) && $this->titre==$beforeDs){
			$ChampRef=$this->findReflexive();
			$sql="UPDATE `".$this->Prefix.$this->titre."` SET `".$ChampRef."`='' WHERE (`Id`=\"".$currentId."\")";
		}
		if (in_array($Relative['Card'],$this->isShortKey) && $this->titre!=$Relative['Titre']){
			$ChampKey=$this->findKey($Relative['Titre'],'parent');
			$sql="UPDATE `".$this->Prefix.$this->titre."` SET `".$ChampKey."`='' WHERE (`Id`=".$currentId.")";
		}
		if (in_array($Relative['Card'],$this->isLongKey)){
			$sql="DELETE FROM `".$this->Prefix.$Relative['Table']."` WHERE ";
			if ($beforeId!=""&&$beforeId!=0){
				$sql.=" (`".$Relative['Titre']."Id`=".$beforeId.")";
			}else{
				$sql.="((`".$Relative['Champ']."`=0) OR (`".$Relative['Champ']."` IS NULL))";
			}
			$sql.= "AND (`".$this->titre."`=".$currentId.")";
		}
		if ($sql!="") return $this->executeSql($sql,"UPDATE_SYS");
		else return true;
	}

	//----------------------------------------------//
	// EXPORTATION					//
	//----------------------------------------------//

	//Exporation d'une table complete dans un fichier
	function fillTable() {
		//On verifie qu il esxiste un fichier
		$Path = "Modules/".$this->Module."/Backup/".$this->titre.".sql";
		if (file_exists($Path)) {
			//Alors on insere les donnÃ©es ligne apres ligne
			$file = fopen($Path,"r");
			while (!feof($file)){
				$ligne=fgets($file,4096);
				$sql="INSERT INTO `".$this->Prefix.$this->titre."` ".$ligne;
				mysqlDriver::executeSql($sql,"INSERT");
			}
		} else $GLOBALS['Systeme']->Log->log("/ERREUR Impossible de trouver le jeu d essai ".$this->titre);
		return true;
	}
	//Exporation d'une table complete dans un fichier
	function saveData(){
		$sql="SELECT * FROM `".$this->Prefix.$this->titre."` as m";
		if (!$resql=$this->executeSql($sql,"SELECT")) return false;
		@mkdir("Modules/".$this->Module."/Backup/");
		$Path="Modules/".$this->Module."/Backup/".$this->titre.".sql";
		$Fichier=fopen($Path,'w');
		$GLOBALS['Systeme']->Log->log("/INFO Enregistrement du fichier  ".$this->titre);
		foreach ($resql as $Selection){
			foreach ($Selection as $Nom=>$Valeur){
				if ($this->isProperties($Nom) || $this->isFKey($Nom )||$Nom=="uid"||$Nom=="gid"||$Nom=="umod"||$Nom=="gmod"||$Nom=="omod") {
					if ($Flag){ $Noms.=','; $Valeurs.=",";}
					$Noms.='`'.$Nom.'`';
					$Valeurs.='"'.htmlentities($Valeur).'"';
					$Flag=true;
				}else{

				}
			}
			$ligne="(".$Noms.") VALUES (".$Valeurs.")\r\n";
			fwrite($Fichier,$ligne);
			$Noms = $Valeurs = $Flag = "";
		}
		return (file_exists($Path)) ? true:false;
	}

	//Renvoie l'ensemble des donnï¿œes propre ï¿œ un group
	function saveGroupData($gId){
		$sql = "select * from `".$this->Prefix.$this->titre."` ";
		$sql .= "where (gId=$gId) OR (omod>1)";
		$requete = mysql_query($sql) or die(mysql_error());
		while ($Resultat = mysql_fetch_assoc($requete)){
			$this->ObjectTable[] = $Resultat;
			$sql = "INSERT INTO `%LEPREFIXE%-".$this->Module."-".$this->titre."` (";
			foreach ($Resultat as $Nom=>$Valeur){
				if ($Flag) {$Noms.=", ";$Valeurs.=", ";}
				$Noms .= '`'.$Nom.'`';
				$Valeurs .= '"'.addslashes($Valeur).'"';
				if (!$Flag) $Flag = true;
			}
			$sql .= $Noms.") VALUES ($Valeurs);";
			$TabSql[] = $sql;
			$Noms = $Valeurs = $Flag = "";
		}
		if (is_array($this->childOf)) foreach ($this->childOf as $Parent){
			if ($Parent["Card"]=="0,n"||$Parent["Card"]=="1,n"){
				$sql = "select * from `".$this->Prefix.$this->titre.$Parent["Titre"]."` ";
				$requete = mysql_query($sql) or die(mysql_error());
				while ($Resultat = mysql_fetch_assoc($requete)){
					//On verifie que l'id appartient bien au User
					$Verif =$GLOBALS["Systeme"]->Modules[$this->Module]->Db->ObjectClass[$Parent["Id"]]->idPossess($Resultat[$Parent["Titre"]."Id"]);
					if ($this->idPossess($Resultat[$this->titre]) && $Verif){
						$sql = "INSERT INTO `%LEPREFIXE%-".$this->Module."-".$this->titre.$Parent["Titre"]."` VALUES ('".$Resultat["Id"]."','".$Resultat["tmsCreate"]."','".$Resultat["userCreate"]."','".$Resultat["tmsEdit"]."','".$Resultat["userEdit"]."','".$Resultat[$this->titre]."','".$Resultat[$Parent["Titre"]."Id"]."');";
						$TabSql[] = $sql;
					}
				}
			}
		}
		return $TabSql;
	}


	//----------------------------------------------//
	// INTERROGATION				//
	//----------------------------------------------//
	//REnvoie le nom de la table de l objectClass en cours
	function getTableName($i=0){
		return $this->Prefix.$this->titre;;
	}

	//Renvoie le proprietaire de l objet en cours
	function idPossess($id){
		if(!count($this->ObjectTable)){
			$sql = "select * from `".$this->Prefix.$this->titre."` ";
			$sql .= "where (gId=$gId) OR (omod>1)";
			$requete = mysql_query($sql);
			while ($Resultat = mysql_fetch_assoc($requete)){
				$this->ObjectTable[] = $Resultat;
			}
		}
		foreach ($this->ObjectTable as $Objet){
			if ($id==$Objet["Id"]) return true;
		}
		return false;
	}

	function countDb() {
		$sql="SELECT COUNT(*) AS Size FROM `".$this->Prefix.$this->titre."`";
		$Result=$this->executeSql($sql,"SELECT_SYS");
		return $Result["Size"];
	}


	//----------------------------------------------//
	// EXECUTION SQL				//
	//----------------------------------------------//
	//Execution d une requete SQL
	function executeSql($sql,$type='SELECT',$GroupBy=""){
		$GLOBALS["Systeme"]->connectSQL();
		//if ($this->titre=="Article") file_put_contents("requete.log",$sql);
		//----------------------------------------------//
		//Gestion des limites et des orders 		//
		//----------------------------------------------//
		$Tab = $GLOBALS["Systeme"]->Modules[$this->Module]->Db->LimRequete;
		$Order = $GLOBALS["Systeme"]->Modules[$this->Module]->Db->Order;
		//----------------------------------------------//
		//#TODO test existance champs order 		//
		//Su oui alors on ordonne sur ce champ egalement//
		//Si non c par Id par defaut			//
		//----------------------------------------------//
		if ($GroupBy!="") $sql.= ' GROUP BY '.$GroupBy;
		if ($type=="SELECT" && strlen($Order[0]) && strlen($Order[1])) {
			$sql.= ' ORDER BY '.((preg_match("#\(#",$Order[0]))?'m.':'').$Order[0].' '.$Order[1];
		}elseif ($type=="SELECT") {
			//Par defaut on doit ranger par le champ de type order
			$Champs = $this->getSpecialProp("order");
			if (is_array($Champs)) {
				$sql.= ' ORDER BY ';
				foreach ($Champs as $Nom=>$Prop) {
					$sql.= 'm.'.$Nom;
					if ($i) $sql.=",";
					$i=true;
				}
				$sql.= ' ASC,m.Id DESC';
			}
		}
		if ($type=="SELECT"&&strlen($Tab[0])&&strlen($Tab[1])) $sql.= ' LIMIT '.$Tab[0].','.$Tab[1];
		if ($type=="SELECT" || $type="SYS_SELECT") $Result = $GLOBALS["Systeme"]->Db[$this->Bdd]->queryAll ( $sql );
		else {
			$Result = $GLOBALS["Systeme"]->Db[$this->Bdd]->exec ( $sql );
		}
		//     		echo $sql.";\r\n";
		/*		  		if ($this->titre=="ProduitReel"){
 			echo "--------------------------------\r\n";
 			echo $sql."\r\n";
			}*/
		/*		echo "--------------------------------\r\n";
		 echo $sql."\r\n";*/
		//$GLOBALS["Systeme"]->Log->log("DEBUG",$sql);
		if (MDB2::isError($Result))echo "ERREURS : ".$sql."\r\n";
		if ($type=="SELECT"||$type=="SELECT_REC"){
			//----------------------------------------------//
			//Gestion des Historiques	 		//
			//----------------------------------------------//
			if (is_array($Result)){
				for($i=0;$i<count($Result);$i++){
					$Result[$i]["ObjectType"] = $this->titre;
					$l=0;
					$StockId[] = $Result[$i]["Id"];
					$LinkNotExist=false;
					while ($LinkNotExist==false){
						if(array_key_exists("__Liaison_J".$l,$Result[$i])){
							$Result[$i]["Historique"][]["Id"] = $Result[$i]["__Liaison_J".$l];
							$Result[$i]["Historique"][count($Result[$i]["Historique"])-1]["ObjectType"] = $Result[$i]["__Liaison_titre_J".$l];
							$l++;
						}else{
							$LinkNotExist=true;
						}
					}
				}
			}
		}

		if (AUTO_COMPLETE_LANG&&$GLOBALS["Systeme"]->LangageDefaut!=$GLOBALS["Systeme"]->DefaultLanguage&&!$GLOBALS["Systeme"]->User->Admin){
			foreach ($GLOBALS["Systeme"]->Conf->get("GENERAL::LANGUAGE") as $Cod=>$Lang) {
				if ($Lang["DEFAULT"]) $DefautPref = $Cod;
			}
			if (is_array($Result)) for( $i=0; $i<sizeof($Result);$i++){
				foreach ($this->Proprietes as $Key=>$Prop){
					//Priorites de langage
					$Special = $this->Proprietes[$Key]["special"];
					if ($Special=="multi"&&$Result[$i][$Key]==""){
						$Result[$i][$Key] = $Result[$i][$DefautPref."-".$Key];
						//print_r($Result[$i]);
					//	echo "CHANGEMENT $Key => ".$Result[$i][$DefautPref."-".$Key]."\r\n";
					}
				}
			}
		}
// 		print_r($Result);
		return $Result;
	}
}
